/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.autoconfigure.jms;

import java.time.Duration;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * JMS 的配置属性。
 *
 * @author Greg Turnquist
 * @author Phillip Webb
 * @author Stephane Nicoll
 * @since 1.0.0
 */
@ConfigurationProperties(prefix = "spring.jms")
public class JmsProperties {

	/**
	 * 默认目标类型是否为主题（topic）。
	 */
	private boolean pubSubDomain = false;

	/**
	 * 连接工厂的 JNDI 名称。设置后，它将优先于其他连接工厂的自动配置。
	 */
	private String jndiName;

	private final Cache cache = new Cache();

	private final Listener listener = new Listener();

	private final Template template = new Template();

	public boolean isPubSubDomain() {
		return this.pubSubDomain;
	}

	public void setPubSubDomain(boolean pubSubDomain) {
		this.pubSubDomain = pubSubDomain;
	}

	public String getJndiName() {
		return this.jndiName;
	}

	public void setJndiName(String jndiName) {
		this.jndiName = jndiName;
	}

	public Cache getCache() {
		return this.cache;
	}

	public Listener getListener() {
		return this.listener;
	}

	public Template getTemplate() {
		return this.template;
	}

	public static class Cache {

		/**
		 * 是否缓存会话。
		 */
		private boolean enabled = true;

		/**
		 * 是否缓存消息消费者。
		 */
		private boolean consumers = false;

		/**
		 * 是否缓存消息生产者。
		 */
		private boolean producers = true;

		/**
		 * 会话缓存的大小（每个 JMS 会话类型）。
		 */
		private int sessionCacheSize = 1;

		public boolean isEnabled() {
			return this.enabled;
		}

		public void setEnabled(boolean enabled) {
			this.enabled = enabled;
		}

		public boolean isConsumers() {
			return this.consumers;
		}

		public void setConsumers(boolean consumers) {
			this.consumers = consumers;
		}

		public boolean isProducers() {
			return this.producers;
		}

		public void setProducers(boolean producers) {
			this.producers = producers;
		}

		public int getSessionCacheSize() {
			return this.sessionCacheSize;
		}

		public void setSessionCacheSize(int sessionCacheSize) {
			this.sessionCacheSize = sessionCacheSize;
		}

	}

	public static class Listener {

		/**
		 * 在启动时自动启动容器。
		 */
		private boolean autoStartup = true;

		/**
		 * 容器的确认模式（Acknowledge mode）。默认情况下，监听器是事务性的并具有自动确认。
		 */
		private AcknowledgeMode acknowledgeMode;

		/**
		 * 并发消费者的最小数量。
		 */
		private Integer concurrency;

		/**
		 * 并发消费者的最大数量。
		 */
		private Integer maxConcurrency;

		/**
		 * 用于接收调用的超时时间。使用 -1 表示无等待接收，使用 0 表示完全无超时。
		 * 后者仅在不运行于事务管理器中时可行，并且通常不被鼓励，因为它会阻止干净的关闭。
		 */
		private Duration receiveTimeout = Duration.ofSeconds(1);

		public boolean isAutoStartup() {
			return this.autoStartup;
		}

		public void setAutoStartup(boolean autoStartup) {
			this.autoStartup = autoStartup;
		}

		public AcknowledgeMode getAcknowledgeMode() {
			return this.acknowledgeMode;
		}

		public void setAcknowledgeMode(AcknowledgeMode acknowledgeMode) {
			this.acknowledgeMode = acknowledgeMode;
		}

		public Integer getConcurrency() {
			return this.concurrency;
		}

		public void setConcurrency(Integer concurrency) {
			this.concurrency = concurrency;
		}

		public Integer getMaxConcurrency() {
			return this.maxConcurrency;
		}

		public void setMaxConcurrency(Integer maxConcurrency) {
			this.maxConcurrency = maxConcurrency;
		}

		public String formatConcurrency() {
			if (this.concurrency == null) {
				return (this.maxConcurrency != null) ? "1-" + this.maxConcurrency : null;
			}
			return ((this.maxConcurrency != null) ? this.concurrency + "-" + this.maxConcurrency
					: String.valueOf(this.concurrency));
		}

		public Duration getReceiveTimeout() {
			return this.receiveTimeout;
		}

		public void setReceiveTimeout(Duration receiveTimeout) {
			this.receiveTimeout = receiveTimeout;
		}

	}

	public static class Template {

		/**
		 * 在没有目标参数的发送和接收操作中使用的默认目标。
		 */
		private String defaultDestination;

		/**
		 * 用于发送调用的传递延迟。
		 */
		private Duration deliveryDelay;

		/**
		 * 传递模式。设置后启用 QoS（服务质量）。
		 */
		private DeliveryMode deliveryMode;

		/**
		 * 发送消息时的优先级。设置后启用 QoS（服务质量）。
		 */
		private Integer priority;

		/**
		 * 发送消息时的存活时间。设置后启用 QoS（服务质量）。
		 */
		private Duration timeToLive;

		/**
		 * 发送消息时是否启用显式 QoS（服务质量）。启用后，在发送消息时将使用传递模式、优先级和存活时间属性。
		 * 当至少有一个这些设置被自定义时，QoS 会自动启用。
		 */
		private Boolean qosEnabled;

		/**
		 * 用于接收调用的超时时间。
		 */
		private Duration receiveTimeout;

		public String getDefaultDestination() {
			return this.defaultDestination;
		}

		public void setDefaultDestination(String defaultDestination) {
			this.defaultDestination = defaultDestination;
		}

		public Duration getDeliveryDelay() {
			return this.deliveryDelay;
		}

		public void setDeliveryDelay(Duration deliveryDelay) {
			this.deliveryDelay = deliveryDelay;
		}

		public DeliveryMode getDeliveryMode() {
			return this.deliveryMode;
		}

		public void setDeliveryMode(DeliveryMode deliveryMode) {
			this.deliveryMode = deliveryMode;
		}

		public Integer getPriority() {
			return this.priority;
		}

		public void setPriority(Integer priority) {
			this.priority = priority;
		}

		public Duration getTimeToLive() {
			return this.timeToLive;
		}

		public void setTimeToLive(Duration timeToLive) {
			this.timeToLive = timeToLive;
		}

		public boolean determineQosEnabled() {
			if (this.qosEnabled != null) {
				return this.qosEnabled;
			}
			return (getDeliveryMode() != null || getPriority() != null || getTimeToLive() != null);
		}

		public Boolean getQosEnabled() {
			return this.qosEnabled;
		}

		public void setQosEnabled(Boolean qosEnabled) {
			this.qosEnabled = qosEnabled;
		}

		public Duration getReceiveTimeout() {
			return this.receiveTimeout;
		}

		public void setReceiveTimeout(Duration receiveTimeout) {
			this.receiveTimeout = receiveTimeout;
		}

	}

	/**
	 * 翻译 {@link javax.jms.Session} 上定义的确认模式。
	 *
	 * <p>
	 * {@link javax.jms.Session#SESSION_TRANSACTED} 未定义，因为我们已经通过调用 {@code setSessionTransacted} 来处理它。
	 */
	public enum AcknowledgeMode {

		/**
		 * 从会话发送或接收的消息被自动确认。这是最简单的模式，并支持一次性消息传递保证。
		 */
		AUTO(1),

		/**
		 * 一旦消息监听器实现调用了 {@link javax.jms.Message#acknowledge()}，消息就会被确认。
		 * 这种模式使应用程序（而不是 JMS 提供者）对消息确认拥有完全的控制权。
		 */
		CLIENT(2),

		/**
		 * 类似于自动确认，但该确认是懒惰的。因此，消息可能会被传递不止一次。这种模式支持至少一次消息传递保证。
		 */
		DUPS_OK(3);

		private final int mode;

		AcknowledgeMode(int mode) {
			this.mode = mode;
		}

		public int getMode() {
			return this.mode;
		}

	}

	public enum DeliveryMode {

		/**
		 * 不要求将消息记录到稳定存储。这是开销最低的传递模式，但如果代理宕机，可能会导致消息丢失。
		 */
		NON_PERSISTENT(1),

		/*
		 * 指示 JMS 提供者将消息作为客户端发送操作的一部分记录到稳定存储。
		 */
		PERSISTENT(2);

		private final int value;

		DeliveryMode(int value) {
			this.value = value;
		}

		public int getValue() {
			return this.value;
		}

	}

}
